﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iNet.Media;
using iNet.Media.Imaging;
using iNet.Tasks;

namespace iNet.Media.Video
{
	/// <summary>
	/// 影片解碼工作基底類別。
	/// </summary>
	public abstract class VideoDecodeTask : MediaDecodeTask
	{
		#region 欄位
		long? _DecodedAverageBitRate;
		long? _DecodedDuration;
		long? _DecodedMaxBitRate;
		IVideo _DecodedVideo;
		double _DecodedVideoFrameRate = double.NaN;
		Size<int>? _DecodedVideoPixelSize;
		VideoDecodeRequests _VideoDecodeRequests;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 VideoDecodeTask 執行個體。
		/// </summary>
		/// <param name="decodingFormat">解碼格式。</param>
		protected VideoDecodeTask(IMediaFormat decodingFormat)
			: base(decodingFormat)
		{ }
		/// <summary>
		/// 初始化新的 VideoDecodeTask 執行個體。
		/// </summary>
		/// <param name="decodingFormat">解碼格式。</param>
		/// <param name="source">影片儲存來源。</param>
		protected VideoDecodeTask(IMediaFormat decodingFormat, MediaStorage source)
			: base(decodingFormat, source)
		{ }
		/// <summary>
		/// 初始化新的 VideoDecodeTask 執行個體。
		/// </summary>
		/// <param name="decodingFormat">解碼格式。</param>
		/// <param name="source">影片儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="videoDecodeReqs">影片解碼請求。</param>
		protected VideoDecodeTask(IMediaFormat decodingFormat, MediaStorage source, MediaDecodeRequests mediaDecodeReqs, VideoDecodeRequests videoDecodeReqs)
			: base(decodingFormat, source, mediaDecodeReqs)
		{
			_VideoDecodeRequests = videoDecodeReqs;
		}
		#endregion
		#region AverageBitRateDecoded
		/// <summary>
		/// 發生在平均位元率資訊解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<long>> AverageBitRateDecoded;
		#endregion
		#region Decode
		/// <summary>
		/// 解碼影片。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="source">影片儲存來源。</param>
		/// <param name="requests">媒體解碼請求。</param>
		/// <returns>True 表示解碼成功，False 表示失敗。</returns>
		protected override bool Decode(TaskVersion version, MediaStorage source, MediaDecodeRequests requests)
		{
			VideoDecodeRequests videoDecodeReqs;
			if (!this.ReadValue<VideoDecodeRequests>(version, ref _VideoDecodeRequests, out videoDecodeReqs))
				return true;
			return this.Decode(version, source, requests, videoDecodeReqs);
		}
		/// <summary>
		/// 解碼影片。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="source">影片儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="videoDecodeReqs">影片解碼請求。</param>
		/// <returns>True 表示解碼成功，False 表示失敗。</returns>
		protected abstract bool Decode(TaskVersion version, MediaStorage source, MediaDecodeRequests mediaDecodeReqs, VideoDecodeRequests videoDecodeReqs);
		#endregion
		#region DecodedAverageBitRate
		/// <summary>
		/// 取得已解碼的平均位元率。
		/// </summary>
		public long? DecodedAverageBitRate
		{
			get
			{
				return _DecodedAverageBitRate;
			}
		}
		#endregion
		#region DecodedDuration
		/// <summary>
		/// 取得已解碼的影片時間長度，單位為毫秒。
		/// </summary>
		public long? DecodedDuration
		{
			get
			{
				return _DecodedDuration;
			}
		}
		#endregion
		#region DecodedMaxBitRate
		/// <summary>
		/// 取得已解碼的最大位元率。
		/// </summary>
		public long? DecodedMaxBitRate
		{
			get
			{
				return _DecodedMaxBitRate;
			}
		}
		#endregion
		#region DecodedVideo
		/// <summary>
		/// 取得已解碼的影片。
		/// </summary>
		public IVideo DecodedVideo
		{
			get
			{
				return _DecodedVideo;
			}
		}
		#endregion
		#region DecodedVideoFrameRate
		/// <summary>
		/// 取得已解碼的視訊畫格速度 (Frames Per Second，FPS)。
		/// </summary>
		public double DecodedVideoFrameRate
		{
			get
			{
				return _DecodedVideoFrameRate;
			}
		}
		#endregion
		#region DecodedVideoPixelSize
		/// <summary>
		/// 取得已解碼的視訊像素大小。
		/// </summary>
		public Size<int>? DecodedVideoPixelSize
		{
			get
			{
				return _DecodedVideoPixelSize;
			}
		}
		#endregion
		#region DurationDecoded
		/// <summary>
		/// 發生在影片時間長度解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<long>> DurationDecoded;
		#endregion
		#region ExecuteChildDecodeTask
		/// <summary>
		/// 使用指定的影片解碼子工作進行解碼。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="decodeTask">指定的影片解碼子工作。</param>
		/// <param name="forwardDecodedResults">是否要將子工作的解碼結果直接作為此工作的解碼結果，預設值為 True。</param>
		/// <param name="forwardMessages">是否要將子工作產生的訊息直接向外發送，預設值為 True。</param>
		/// <returns>子工作執行結果。</returns>
		/// <exception cref="ArgumentException">decodeTask 為工作本身。</exception>
		/// <exception cref="ArgumentNullException">version 或 decodeTask 為 Null (Visual Basic 為 Nothing)。</exception>
		protected TaskState ExecuteChildDecodeTask(TaskVersion version, VideoDecodeTask decodeTask, bool forwardDecodedResults = true, bool forwardMessages = true)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (decodeTask == null)
				throw new ArgumentNullException("decodeTask");
			if (decodeTask == this)
				throw new ArgumentException();

			//準備事件處理方法
			EventHandler<DataEventArgs<long>> avgBitRateDecodedHandler = null;
			EventHandler<DataEventArgs<long>> durationDecodedHandler = null;
			EventHandler<DataEventArgs<double>> frameRateDecodedHandler = null;
			EventHandler<DataEventArgs<Size<int>>> frameSizeDecodedHandler = null;
			EventHandler<DataEventArgs<long>> maxBitRateDecodedHandler = null;
			EventHandler<DataEventArgs<IMetadata>> metadataDecodedHandler = null;
			EventHandler<DataEventArgs<IImage>> thumbDecodedHandler = null;
			EventHandler<DataEventArgs<IVideo>> videoDecodedHandler = null;
			if (forwardDecodedResults)
			{
				avgBitRateDecodedHandler = (sender, e) =>
				{
					this.SetDecodedAverageBitRate(version, e.Data);
				};
				durationDecodedHandler = (sender, e) =>
				{
					this.SetDecodedDuration(version, e.Data);
				};
				frameRateDecodedHandler = (sender, e) =>
				{
					this.SetDecodedVideoFrameRate(version, e.Data);
				};
				frameSizeDecodedHandler = (sender, e) =>
				{
					this.SetDecodedVideoPixelSize(version, e.Data);
				};
				maxBitRateDecodedHandler = (sender, e) =>
				{
					this.SetDecodedMaxBitRate(version, e.Data);
				};
				metadataDecodedHandler = (sender, e) =>
				{
					this.SetDecodedMetadata(version, e.Data);
				};
				thumbDecodedHandler = (sender, e) =>
				{
					this.SetDecodedThumbnailImage(version, e.Data);
				};
				videoDecodedHandler = (sender, e) =>
				{
					this.SetDecodedVideo(version, e.Data);
				};
				decodeTask.AverageBitRateDecoded += avgBitRateDecodedHandler;
				decodeTask.DurationDecoded += durationDecodedHandler;
				decodeTask.MaxBitRateDecoded += maxBitRateDecodedHandler;
				decodeTask.MetadataDecoded += metadataDecodedHandler;
				decodeTask.ThumbnailImageDecoded += thumbDecodedHandler;
				decodeTask.VideoDecoded += videoDecodedHandler;
				decodeTask.VideoFrameRateDecoded += frameRateDecodedHandler;
				decodeTask.VideoPixelSizeDecoded += frameSizeDecodedHandler;
			}

			//解碼影像
			try
			{
				decodeTask.MediaDecodeRequests = this.MediaDecodeRequests;
				decodeTask.VideoDecodeRequests = _VideoDecodeRequests;
				return this.ExecuteChildTask(version, decodeTask, forwardMessages);
			}
			finally
			{
				if (forwardDecodedResults)
				{
					decodeTask.AverageBitRateDecoded -= avgBitRateDecodedHandler;
					decodeTask.DurationDecoded -= durationDecodedHandler;
					decodeTask.MaxBitRateDecoded -= maxBitRateDecodedHandler;
					decodeTask.MetadataDecoded -= metadataDecodedHandler;
					decodeTask.ThumbnailImageDecoded -= thumbDecodedHandler;
					decodeTask.VideoDecoded -= videoDecodedHandler;
					decodeTask.VideoFrameRateDecoded -= frameRateDecodedHandler;
					decodeTask.VideoPixelSizeDecoded -= frameSizeDecodedHandler;
				}
			}
		}
		#endregion
		#region MaxBitRateDecoded
		/// <summary>
		/// 發生在最大位元率資訊解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<long>> MaxBitRateDecoded;
		#endregion
		#region ResetOverride
		/// <summary>
		/// 重設工作狀態。
		/// </summary>
		protected override void ResetOverride()
		{
			//重設狀態
			_DecodedAverageBitRate = null;
			_DecodedDuration = null;
			_DecodedMaxBitRate = null;
			_DecodedVideo = null;
			_DecodedVideoFrameRate = double.NaN;
			_DecodedVideoPixelSize = null;
			_VideoDecodeRequests = 0;

			//呼叫基底
			base.ResetOverride();
		}
		#endregion
		#region SetDecodedAverageBitRate
		/// <summary>
		/// 設定已解碼的平均位元率資訊。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="bitRate">平均位元率。</param>
		protected void SetDecodedAverageBitRate(TaskVersion version, long bitRate)
		{
			if (this.SetDecodedBitRate(version, ref _DecodedAverageBitRate, ref bitRate))
			{
				if (this.AverageBitRateDecoded != null)
					this.AverageBitRateDecoded(this, new DataEventArgs<long>(bitRate));
			}
		}
		#endregion
		#region SetDecodedBitRate
		bool SetDecodedBitRate(TaskVersion version, ref long? bitRateField, ref long bitRate)
		{
			if (bitRate < 0)
				bitRate = 0;
			lock (this.SyncRoot)
			{
				if (this.CurrentVersion != version)
					return false;
				if (bitRateField != null && bitRateField.Value == bitRate)
					return false;
				bitRateField = bitRate;
				return true;
			}
		}
		#endregion
		#region SetDecodedDuration
		/// <summary>
		/// 設定已解碼的影片時間長度。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="duration">影片時間長度。</param>
		protected void SetDecodedDuration(TaskVersion version, long duration)
		{
			lock (this.SyncRoot)
			{
				if (this.CurrentVersion != version)
					return;
				if (_DecodedDuration != null && _DecodedDuration.Value == duration)
					return;
				_DecodedDuration = duration;
			}
			if (this.DurationDecoded != null)
				this.DurationDecoded(this, new DataEventArgs<long>(duration));
		}
		#endregion
		#region SetDecodedMaxBitRate
		/// <summary>
		/// 設定已解碼的最大位元率資訊。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="bitRate">最大位元率。</param>
		protected void SetDecodedMaxBitRate(TaskVersion version, long bitRate)
		{
			if (this.SetDecodedBitRate(version, ref _DecodedMaxBitRate, ref bitRate))
			{
				if (this.MaxBitRateDecoded != null)
					this.MaxBitRateDecoded(this, new DataEventArgs<long>(bitRate));
			}
		}
		#endregion
		#region SetDecodedVideo
		/// <summary>
		/// 設定已解碼的影片。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="video">影片。</param>
		/// <returns>True 表示設定完成，False 表示因狀態錯誤而沒有設定完成。</returns>
		protected bool SetDecodedVideo(TaskVersion version, IVideo video)
		{
			lock (this.SyncRoot)
			{
				if (this.CurrentVersion != version)
					return false;
				if (_DecodedVideo == video)
					return true;
				_DecodedVideo = video;
			}
			if (this.VideoDecoded != null)
				this.VideoDecoded(this, new DataEventArgs<IVideo>(video));
			return true;
		}
		#endregion
		#region SetDecodedVideoFrameRate
		/// <summary>
		/// 設定已解碼的影片框架速度。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="frameRate">影片框架速度。</param>
		protected void SetDecodedVideoFrameRate(TaskVersion version, double frameRate)
		{
			if (frameRate < 0)
				frameRate = double.NaN;
			lock (this.SyncRoot)
			{
				if (this.CurrentVersion != version)
					return;
				if (_DecodedVideoFrameRate == frameRate)
					return;
				_DecodedVideoFrameRate = frameRate;
			}
			if (this.VideoFrameRateDecoded != null)
				this.VideoFrameRateDecoded(this, new DataEventArgs<double>(frameRate));
		}
		#endregion
		#region SetDecodedVideoPixelSize
		/// <summary>
		/// 設定已解碼的影片像素大小。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="pixelSize">影片像素大小。</param>
		protected void SetDecodedVideoPixelSize(TaskVersion version, Size<int> pixelSize)
		{
			lock (this.SyncRoot)
			{
				if (this.CurrentVersion != version)
					return;
				if (_DecodedVideoPixelSize != null && _DecodedVideoPixelSize.Value == pixelSize)
					return;
				_DecodedVideoPixelSize = pixelSize;
			}
			if (this.VideoPixelSizeDecoded != null)
				this.VideoPixelSizeDecoded(this, new DataEventArgs<Size<int>>(pixelSize));
		}
		#endregion
		#region VideoDecoded
		/// <summary>
		/// 發生在影片解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<IVideo>> VideoDecoded;
		#endregion
		#region VideoDecodeRequests
		/// <summary>
		/// 取得或設定影片解碼工作請求。
		/// </summary>
		public VideoDecodeRequests VideoDecodeRequests
		{
			get
			{
				return _VideoDecodeRequests;
			}
			set
			{
				this.SetInitializingParameter<VideoDecodeRequests>(ref _VideoDecodeRequests, value);
			}
		}
		#endregion
		#region VideoFrameRateDecoded
		/// <summary>
		/// 發生在視訊框架速度 (Frames Per Second，FPS) 解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<double>> VideoFrameRateDecoded;
		#endregion
		#region VideoPixelSizeDecoded
		/// <summary>
		/// 發生在視訊畫面大小解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<Size<int>>> VideoPixelSizeDecoded;
		#endregion
	}
	#region VideoDecodeRequests
	/// <summary>
	/// 表示影片解碼的請求組合。
	/// </summary>
	[Flags]
	public enum VideoDecodeRequests
	{
		/// <summary>
		/// 全部請求。
		/// </summary>
		All = (DecodeBitRate | DecodeDuration | DecodeVideo | DecodeVideoFrameRate | DecodeVideoPixelSize),
		/// <summary>
		/// 解碼位元率。
		/// </summary>
		DecodeBitRate = 0x1,
		/// <summary>
		/// 解碼影片時間長度。
		/// </summary>
		DecodeDuration = 0x2,
		/// <summary>
		/// 解碼影片。
		/// </summary>
		DecodeVideo = 0x4,
		/// <summary>
		/// 解碼視訊畫格速度。
		/// </summary>
		DecodeVideoFrameRate = 0x8,
		/// <summary>
		/// 解碼視訊像素大小。
		/// </summary>
		DecodeVideoPixelSize = 0x10,
	}
	#endregion
}
